#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <signal.h>

#define PERM S_IRUSR|S_IWUSR|IPC_CREAT

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
#define gettid() syscall(__NR_gettid)
  /* wrap the system call syscall(__NR_gettid), __NR_gettid = 224 */
#define gettidv2() syscall(SYS_gettid) /* a traditional wrapper */

#define STACK_SIZE 1024*1024 /* 1Mib. question: what is the upperbound of STACK_SIZE */
int pipeline[2];

static int child_func1(void *arg)
{
    void *shmptr = NULL;
    struct shared_struct *shared;
    int shmid;
    key_t key;
 
    key_t* keyptr = (key_t*)arg;
    key = *keyptr;

    printf("%*sshmread: IPC key = %x\n", 30, " ", key);
    
    shmid = shmget((key_t)key, sizeof(int), 0666|PERM);
    if (shmid == -1) {
        ERR_EXIT("shread: shmget()");
    }

    shmptr = shmat(shmid, 0, 0);

    int* name = (int*) shmptr;
    printf("child namespace %d\n", *name);

    return 0;
}

int main(int argc,char **argv)
{
    void *shmptr = NULL;
    struct shared_struct *shared;
    int shmid;
    key_t key;
 
    key = ftok("log/thread-1.log", 0x27);
    printf("%*sshmread: IPC key = %x\n", 30, " ", key);
    
    shmid = shmget((key_t)key, sizeof(int), 0666|PERM);
    if (shmid == -1) {
        ERR_EXIT("shread: shmget()");
    }

    shmptr = shmat(shmid, 0, 0);

    int * name = (int*)shmptr;
    *name = 1;
    pipeline[0] = 1;
    
    printf("parent namespace %d\n", *name);

    char *stack1 = malloc(STACK_SIZE*sizeof(char)); /* allocating from heap, safer than stack1[STACK_SIZE] */
    pid_t chdtid1;
    unsigned long flags = 0;
    char buf[100]; /* a global variable has the same behavior */

    if(!stack1) {
        perror("malloc()");
        exit(1);
    }
    
      /* set CLONE flags */
    if((argc > 1) && (!strcmp(argv[1], "newipc"))) {
        flags |= CLONE_NEWIPC;
    }

    sprintf(buf,"I am parent, my pid = %d", getpid());
    printf("%s\n", buf);
    sleep(1);
    printf("parrent clone ...\n");

      /* creat child thread, top of child stack is stack+STACK_SIZE */
    chdtid1 = clone(child_func1, stack1 + STACK_SIZE, flags |SIGCHLD , &key); /* what happened if without SIGCHLD */
    if(chdtid1 == -1) {
        perror("clone1()");
        exit(1);
    }

    char pipebuf[20];

    read(pipeline[0], pipebuf, 20);

    printf("read pipe %s\n", pipebuf);

    
    printf("parent waiting ... \n");

    int status = 0;
    if(waitpid(-1, &status, 0) == -1) { /* wait for any child existing, may leave some child defunct */
        perror("wait()");
    }
  
//waitpid(chdtid1, &status, 0);
//waitpid(chdtid2, &status, 0);
  
    sleep(1);

    printf("%s\n", buf);

    //system("ps");
    
    free(stack1);
    stack1 = NULL;
    
    return 0;
}

